#-*- coding: utf-8 -*-
'''
Twitter 로부터 Tweet 들을 긁어온다.
'''
import datetime
import json
import os
import sys

import tweepy
import tweepy.error

FILE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(FILE_PATH)

from db import tw_status
import settings
import util


def get_api():
    '''
    settings.py 에 저장된 정보를 사용하여 Tweepy API 를 반환한다.

    @rtype: tweepy.API
    @return: Tweepy API
    '''

    auth = tweepy.OAuthHandler(
            settings.CONSUMER_KEY, settings.CONSUMER_SECRET)
    auth.set_access_token(
            settings.OAUTH_KEY, settings.OAUTH_SECRET)
    api = tweepy.API(auth)
    return api


def status_to_json(status):
    '''
    Tweepy Status 인스턴스를 JSON serialized string 으로 변환한다.

    @type  status: tweepy.models.Status
    @param status: JSON serialized string 으로 변환할 트윗메시지
    @rtype: str
    @return: JSON encoded string
    '''

    dictionary = util.filter_dict(status.__dict__, "_api")
    dictionary['user'] = util.filter_dict(dictionary['user'].__dict__, "_api")
    dictionary['author'] = util.filter_dict(dictionary['author'].__dict__, "_api")

    # Datetime 자료형을 JSON 으로 변환하는 부분
    dthandler = lambda obj: obj.isoformat() if isinstance(
            obj, datetime.datetime) else None
    result = json.dumps(dictionary, default=dthandler)
    return result



class API(object):

    def __init__(self, collection):
        self.api = get_api()
        self.status_collection = collection

    def store_timeline(self, timeline):
        '''
        @type  timeline: list<tweepy.models.Status>
        @param timeline: DB에 저장하고자 하는 Status 들의 list
        '''
        result = [status_to_json(x) for x in timeline]
        self.status_collection.insert(result)

    def call_api(self, method, **kwargs):
        MAX_RETRY = 5
        for idx in xrange(MAX_RETRY):
            try:
                return method(**kwargs)
            except tweepy.error.TweepyError as e:
                if e.response == 502:
                    print "Error 502, simply retrying"
                    continue
        return []

    def get_user_timeline (self, screen_name):
        return self.call_api(self.api.user_timeline,
                count=200, screen_name=screen_name)

    def get_home_timeline(self):
        return self.call_api(self.api.home_timeline,
                count=200)

    def get_older_home_timeline(self):
        return self.call_api(self.api.home_timeline,
                count=200, max_id=self.status_collection.get_oldest_message_id())

    def get_older_user_timeline(self, screen_name):
        return self.call_api(self.api.user_timeline,
                count=200,
                max_id=self.status_collection.get_oldest_message_id(screen_name),
                screen_name=screen_name)

    def get_newer_home_timeline(self):
        return self.call_api(self.api.home_timeline,
                count=200, since_id=self.status_collection.get_newest_message_id())

    def get_newer_user_timeline(self, screen_name):
        return self.call_api(self.api.user_timeline,
                count=200,
                since_id=self.status_collection.get_newest_message_id(screen_name),
                screen_name=screen_name)

    def store_newer_home_timeline(self):
        '''
        DB 에 저장되어 있는 tweet 이후 올라온 tweet 을 한 차례 저장한다.

        @rtype: bool
        @return: 추가로 저장된 tweet 이 있는지의 여부
        '''
        timeline = self.get_newer_home_timeline()
        if len(timeline) == 1:
            if timeline[0].id == self.status_collection.get_newest_message_id():
                return False
        self.store_timeline(timeline)
        return True

    def store_newest_home_timeline(self):
        '''
        DB 에 저장되어 있는 tweet 이후로 올라온 모든 tweet 을 저장해 낸다.
        '''
        while self.store_newer_home_timeline():
            pass

    def store_older_home_timeline(self):
        '''
        DB 에 저장되어 있는 tweet 이후 올라온 tweet 을 한 차례 저장한다.

        @rtype: bool
        @return: 추가로 저장된 tweet 이 있는지의 여부
        '''
        timeline = self.get_older_home_timeline()
        if len(timeline) == 1:
            if timeline[0].id == self.status_collection.get_newest_message_id():
                return False
        self.store_timeline(timeline)
        return True

    def store_oldest_home_timeline(self):
        '''
        DB 에 저장되어 있는 tweet 이전에 올라온 모든 tweet 을 저장해 낸다.
        '''
        while self.store_older_home_timeline():
            pass

    def store_newer_user_timeline(self, screen_name):
        '''
        DB 에 저장되어 있는 tweet 이후 올라온 tweet 을 한 차례 저장한다.

        @rtype: bool
        @return: 추가로 저장된 tweet 이 있는지의 여부
        '''
        timeline = self.get_newer_user_timeline(screen_name)
        if len(timeline) == 1:
            if timeline[0].id == self.status_collection.get_newest_message_id(screen_name):
                return False
        self.store_timeline(timeline)
        return True

    def store_newest_user_timeline(self, screen_name):
        '''
        DB 에 저장되어 있는 tweet 이후로 올라온 모든 tweet 을 저장해 낸다.
        '''
        while self.store_newer_user_timeline(screen_name):
            pass

    def store_older_user_timeline(self, screen_name):
        '''
        DB 에 저장되어 있는 tweet 이후 올라온 tweet 을 한 차례 저장한다.

        @rtype: bool
        @return: 추가로 저장된 tweet 이 있는지의 여부
        '''
        timeline = self.get_older_user_timeline(screen_name)
        if len(timeline) == 1:
            if timeline[0].id == self.status_collection.get_newest_message_id(screen_name):
                return False
        self.store_timeline(timeline)
        return True

    def store_oldert_user_timeline(self, screen_name):
        '''
        DB 에 저장되어 있는 tweet 이전에 올라온 모든 tweet 을 저장해 낸다.
        '''
        while self.store_older_user_timeline(screen_name):
            pass

# Global Variable
api = None

def main():
    global api
    api = API(tw_status.StatusCollection())
    #api.store_timeline(api.get_home_timeline())
    #print "========================================"
    #api.store_timeline(api.get_newer_home_timeline())
    #print "========================================"
    #api.store_newest_home_timeline()
    #api.store_oldest_home_timeline()
    #api.store_timeline(api.get_user_timeline('mest4u'))
    #api.store_newest_user_timeline('mest4u')
    #api.store_oldest_user_timeline('mest4u')

if __name__ == "__main__":
    main()
